package com.key.gradle.test.web;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.key.gradle.test.service.AsyncTestService;

@RestController
@RequestMapping("/test/async")
public class AsyncTestController {
	
	private final static Logger logger = LoggerFactory.getLogger(AsyncTestController.class);
	
	@Autowired
	private AsyncTestService asyncTestService;
	
	private int randomInt(int min, int max) {
		return min + (int) (Math.random() * ((max - min) + 1));
	}

	@RequestMapping(value = "/default", method = RequestMethod.GET)
	@ResponseBody
	public Map<String, Object> testAsyncDefault(HttpSession session) {
		int taskNo = this.randomInt(0, 100);
		logger.info("Execute method asynchronously default - [{}] before", taskNo);
		Future<String> future = asyncTestService.runDefaultAsyncExecutor(taskNo);
		
		session.setAttribute("async-task-" + taskNo, future);
		
		Map<String, Object> result = new HashMap<String, Object>();
		result.put("taskNo", taskNo);
		
		logger.info("Execute method asynchronously default - [{}] return", taskNo);
		return result;
	}
	
	@RequestMapping(value = "/default/status/{taskNo}", method = RequestMethod.GET)
	@ResponseBody
	public Map<String, Object> testAsyncDefault(HttpSession session, @PathVariable Integer taskNo) {
		
		logger.info("Execute method asynchronously default - [{}] check status", taskNo);
		Map<String, Object> result = new HashMap<String, Object>();
		
		@SuppressWarnings("unchecked")
		Future<String> future = (Future<String>) session.getAttribute("async-task-" + taskNo);
		
		if (future == null) {
			result.put("status", null);
		} else if (future.isDone()) {
			result.put("status", true);
			try {
				result.put("result", future.get());
			} catch (InterruptedException e) {
				logger.error("Execute method asynchronously default - [" + taskNo + "] check status InterruptedException", e);
			} catch (ExecutionException e) {
				logger.error("Execute method asynchronously default - [" + taskNo + "] check status ExecutionException", e);
			}
		} else {
			result.put("status", false);
		}
		
		return result;
	}
	
	@RequestMapping(value = "/another", method = RequestMethod.GET)
	@ResponseBody
	public Map<String, Object> testAsyncAnother() {
		int taskNo = this.randomInt(0, 100);
		logger.info("Execute method asynchronously another - [{}] before", taskNo);
		asyncTestService.runAnotherAsyncExecutor(taskNo);
		
		Map<String, Object> result = new HashMap<String, Object>();
		result.put("taskNo", taskNo);
		
		logger.info("Execute method asynchronously another - [{}] return", taskNo);
		return result;
	}
	
}
